import 'package:flutter/material.dart';

abstract class DropdownOption {
  String get description;
}

class StringDropdownOption extends DropdownOption {
  final String text;

  StringDropdownOption(this.text);

  @override
  String get description => text;
}

class DropdownFormFieldWidget<T extends DropdownOption>
    extends StatelessWidget {
  final List<T> options;
  final EdgeInsetsGeometry? contentPadding;
  final TextStyle? errorStyle;
  final TextStyle? valueStyle;
  final TextStyle? hintStyle;
  final String? hintText;
  final T? value;
  final FormFieldValidator<T>? validator;
  final PopupMenuItemSelected<T> onSelected;
  final double? popMenuWidth;
  final bool wrapOptions;
  final double wrapRunSpacing;
  final double wrapSpacing;
  final Offset offset;

  const DropdownFormFieldWidget({
    Key? key,
    required this.options,
    this.contentPadding,
    this.valueStyle,
    this.errorStyle,
    this.hintStyle,
    this.value,
    this.hintText,
    this.validator,
    required this.onSelected,
    this.popMenuWidth,
    this.wrapOptions = false,
    this.wrapRunSpacing = 10,
    this.wrapSpacing = 10,
    this.offset = const Offset(8, 8),
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FormField<T>(
      builder: (FormFieldState<dynamic> field) {
        return buildInputDecorator(context, options, field);
      },
      validator: validator,
    );
  }

  InputDecorator buildInputDecorator(BuildContext context, List<T> items,
      FormFieldState<dynamic> formFieldState) {
    return InputDecorator(
      decoration: InputDecoration(
        border: OutlineInputBorder(),
        contentPadding: contentPadding,
        errorText: formFieldState.errorText,
        errorStyle: errorStyle,
      ),
      child: PopupMenuButton<T>(
        offset: offset,
        child: Row(
          children: [
            if (value?.description.isNotEmpty ?? false)
              Text(value!.description, style: valueStyle)
            else
              Text(hintText!, style: hintStyle),
            Spacer(),
            Icon(Icons.keyboard_arrow_down),
          ],
        ),
        itemBuilder: (BuildContext context) {
          return buildOptions(context, options);
        },
        onSelected: onSelected,
        onCanceled: () {
          print("onCanceled called");
        },
      ),
    );
  }

  List<PopupMenuEntry<T>> buildOptions(BuildContext context, List<T> items) {
    if (wrapOptions == true)
      return [
        PopupMenuItem(
          value: null,
          textStyle: valueStyle,
          child: Wrap(
            runSpacing: wrapRunSpacing,
            spacing: wrapSpacing,
            children: [
              for (T bean in items)
                OutlinedButton(
                  style: OutlinedButton.styleFrom(padding: EdgeInsets.all(0)),
                  onPressed: () {
                    Navigator.of(context).pop(bean);
                  },
                  child: Text(bean.description, style: valueStyle),
                ),
            ],
          ),
        )
      ];
    return [
      for (T bean in items)
        PopupMenuItem(
          value: bean,
          textStyle: valueStyle,
          child: SizedBox(
            width: popMenuWidth,
            child: Text(bean.description, style: valueStyle),
          ),
        )
    ];
  }
}
